package common;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

import math.HubertEstimateIterMin;
import math.KurtosisBasedMethod;
import math.LeastAbsMethodIterMin;
import math.LeastSquareMethod;
import math.MEstimate;
import math.WLeastSquareMethod;

import math.common.MathCommon;
import math.probability.CompDistribution;
import math.probability.ExpDistribution;
import math.probability.NormalDistribution;
import math.probability.ProbDistribution;

public class StabilityAnalysis {
	
	public void testEstimates(String fileName, Map <String, MEstimate> estimates,
						ProbDistribution distX, 
						ProbDistribution distEps,
						ProbDistribution distXi,
						int N, int M)  {
	
		
		Double b1 = 1.00;
		Double b0 = 0.0;

		
		StringBuilder builder = new StringBuilder();
		List<Double> b = new ArrayList<Double>();
		for (String estName : estimates.keySet()) {
			Random r = new Random(0);
			for (int j=0; j<M; j++) {
				StructuralModel model =  new StructuralModel(N,distX, distXi, distEps, b0, b1);
				Map<Double, Double> data = MathCommon.Normalize(model.getData());
				List<Double> V = new ArrayList<Double> (data.values());
				List<Double> U = new ArrayList<Double> (data.keySet());
				//error point
				U.add(6.0);
				V.add(60.0);
				b.add(estimates.get(estName).estimate(V, U));
			}
			int p5 =  new Double(M * 0.05).intValue();
			int p95 = new Double(M * 0.95).intValue();
			Collections.sort(b);
			Double est = (b.get(p5)+b.get(p95))/2;
			builder.append(String.format("%s,%d,%d,%s,%s,%s, %2.4f,(%2.4f;%2.4f), %2.4f, %2.4f\n", 
				estName,N,M,distX.toString(),distXi.toString(),distEps.toString(),
						est, b.get(p5),b.get(p95), b.get(p95)-b.get(p5),Math.abs((b1-est)/b1)));
			b.clear();
		}
			
		PrintWriter out = null;
		try {
			File outFile = new File (fileName); 
			out = new PrintWriter(new FileOutputStream(fileName, true));
			if (outFile.length() == 0)
				out.println("Estimator,N,M,X,Xi,Eps, b1, b1 95% c.i., c.i. length, err");
			out.print(builder.toString());
			out.flush();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			if (out != null)
				out.close();
		}
		

		
	}
	
	public void printEx(String fileName, Map <String, MEstimate> estimates,
			ProbDistribution distX, 
			ProbDistribution distEps,
			ProbDistribution distXi,
			int N)  {

		Double b1 = 1.00;
		Double b0 = 0.0;

		StructuralModel model =  new StructuralModel(N,distX, distXi, distEps, b0, b1);
		Map<Double, Double> data = MathCommon.Normalize(model.getData());
		List<Double> V = new ArrayList<Double> (data.values());
		List<Double> U = new ArrayList<Double> (data.keySet());
		//error point
//		U.add(30.0);
//		V.add(3.0);
		
		StringBuilder builder = new StringBuilder();
		builder.append("U,V,");
		Map<String,Double> estValues = new TreeMap<String,Double>();
		for (String estName : estimates.keySet()) {
			estValues.put(estName, estimates.get(estName).estimate(V, U));
			builder.append(String.format("%s(%2.3f),",estName,estValues.get(estName)));
		}
		builder.append(String.format("\n",""));
		for (int i = 0; i < U.size(); i++) {
			builder.append(String.format("%2.4f,%2.4f,", U.get(i), V.get(i)));
			for (String estName : estimates.keySet()) {
				builder.append(estValues.get(estName)*U.get(i)).append(",");
			}
			builder.append(String.format("\n",""));
		}

		PrintWriter out = null;
		try {
			out = new PrintWriter(new FileOutputStream(fileName));
			out.print(builder.toString());
			out.flush();

		} catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			if (out != null)
				out.close();
		}
	}
	
	void doTest () {
		Map <String, MEstimate> estimates = new TreeMap<String, MEstimate>();
		estimates.put("LSM_errPointV", new LeastSquareMethod());
		estimates.put("WLSM_errPointV", new WLeastSquareMethod());		
		estimates.put("Hubert_errPointV", new HubertEstimateIterMin(0.0001));
		estimates.put("LAM_errPointV", new LeastAbsMethodIterMin(0.0001));
		
		

//		testEstimates("testEst.csv",estimates,new ExpDistribution(1.0), new NormalDistribution(0.0,0.2),
//				new NormalDistribution(0.0, 0.0), 500, 1000);
//
//		testEstimates("testEst.csv",estimates,new ExpDistribution(1.0), 
//				new CompDistribution(0.01, new NormalDistribution(0.0,0.2), new NormalDistribution(0.0,10.0)),
//				new NormalDistribution(0.0, 0.0), 500, 1000);
//		
//		testEstimates("testEst.csv",estimates,new ExpDistribution(1.0), 
//				new CompDistribution(0.1, new NormalDistribution(0.0,0.2), new NormalDistribution(0.0,10.0)),
//				new NormalDistribution(0.0, 0.0), 500, 1000);
//		
		
		
		
		
		
		
		
//		
//		testEstimates("testEst.csv",estimates,new ExpDistribution(1.0), new NormalDistribution(0.0,0.2),
//									new NormalDistribution(0.0, 0.3), 500, 1000);
//		testEstimates("testEst.csv",estimates,new ExpDistribution(1.0), new NormalDistribution(0.0,0.2),
//				new CompDistribution(0.05, new NormalDistribution(0.0,0.3),new NormalDistribution(0.0,3.0)), 500, 1000);
//		testEstimates("testEst.csv",estimates,new ExpDistribution(1.0), new NormalDistribution(0.0,0.2),
//				new CompDistribution(0.1, new NormalDistribution(0.0,0.3),new NormalDistribution(0.0,3.0)), 500, 1000);
//
//		
		
		
		
		
		testEstimates("testEstErrorPoint.csv",estimates,new ExpDistribution(1.0), new NormalDistribution(0.0,0.2),
				new NormalDistribution(0.0, 0.3), 500, 1000);

//		printEx("testEstEx2.csv",estimates,new ExpDistribution(1.0), 
//				new CompDistribution(0.01, new NormalDistribution(0.0,0.2), new NormalDistribution(0.0,10.0)),
//				new NormalDistribution(0.0, 0.0), 500);
//		
//		printEx("testEstEx3.csv",estimates,new ExpDistribution(1.0), 
//				new CompDistribution(0.1, new NormalDistribution(0.0,0.2), new NormalDistribution(0.0,10.0)),
//				new NormalDistribution(0.0, 0.0), 500);
		
		
		
	}
	

	
	public void calcE () {
		ProbDistribution distX = new ExpDistribution(1.0);
//		ProbDistribution distX = new NormalDistribution(3.0,0.8); 
		ProbDistribution distEps = new NormalDistribution(0.0,0.3);
//		ProbDistribution distXi = new NormalDistribution(0.0,0.1);
		ProbDistribution distXi = new CompDistribution(0.05, new NormalDistribution(0.0,0.1),
				new NormalDistribution(0.0,1.0));
		Double b0 = 0.0;
		Double b1 = 1.0;
		int n = 500;
		StructuralModel model = new StructuralModel(n,distX, distXi, distEps, b0, b1);
		
//		EIVKurtMethod
		
//		Map<Double, Double> data = MathCommon.Normalize(model.getData());
		
		model.printData("StabilityAnalysis_data.csv");
//		System.out.println(new EIVKurtMethod().estimate(model.getSmplV(), model.getSmplU()));

		
		
				

	}
	
	public static void main(String[] args) {
		StabilityAnalysis app = new StabilityAnalysis();
		app.doTest();
	}

}
